using System;
using System.Windows.Media;
using System.Windows;

namespace Windy.TurtleDrawing
{
    public class Turtle : IDisposable
    {
        protected StreamGeometryContext Context;
        public bool IsInitialized { get; protected set; }

        public Turtle(StreamGeometryContext context)
        {
            this.Context = context;
            IsInitialized = false;
        }

        public Turtle(StreamGeometryContext context, Point startPoint, double direction = 0, bool isPloting = true, bool isFilled = false, bool isClosed = false)
            : this(context)
        {
            this.Context = context;

            StartTrack(startPoint, direction, isPloting, isFilled, isClosed);
        }

        public void StartTrack(Point startPoint, double direction = 0, bool isPloting = true, bool isFilled = false, bool isClosed = false)
        {
            IsInitialized = false;

            Position = startPoint;
            DirectionRadian = direction;
            this.IsFilled = isFilled;
            this.IsClosed = isClosed;
            this.IsPloting = true;

            Context.BeginFigure(startPoint, isFilled, isClosed);

            IsInitialized = true;
        }

        public bool IsFilled { get; private set; }
        public bool IsClosed { get; private set; }

        public bool IsPloting { get; set; }

        private Point position;
        public Point Position
        {
            get { return position; }
            set
            {
                if (Position == value)
                    return;

                position = value;

                if (IsInitialized)
                    Context.LineTo(value, IsPloting, false);
            }
        }

        public double DirectionRadian
        {
            get { return DirectionDegree.ToRadian(); }
            set { DirectionDegree = value.ToDegree(); }
        }

        private double directionDegree;
        public double DirectionDegree
        {
            get { return directionDegree; }
            set
            {
                directionDegree = value.NormalizeAngleDegree();
            }
        }

        public void TurnRadian(double angle)
        {
            DirectionRadian += angle;
        }

        public void TurnDegree(double angle)
        {
            DirectionDegree += angle;
        }

        public void TurnTo(double angle)
        {
            DirectionRadian = angle;
        }

        public void TurnToDegree(double angle)
        {
            DirectionDegree = angle;
        }

        public void MoveTo(Point position)
        {
            Position = position;
        }

        public void MoveHorizontal(double xOffset)
        {
            Position = new Point(Position.X + xOffset, Position.Y);
        }

        public void MoveVertial(double yOffset)
        {
            Position = new Point(Position.X, Position.Y + yOffset);
        }

        public void MoveForward(double distance)
        {
            MoveInteral(distance, 0);
        }

        public void MoveBackward(double distance)
        {
            MoveInteral(distance, 180);
        }

        public void MoveLeft(double distance)
        {
            MoveInteral(distance, -90);
        }

        public void MoveRight(double distance)
        {
            MoveInteral(distance, 90);
        }

        protected void MoveInteral(double distance, double angleOffset)
        {
            var finalAngle = (DirectionDegree + angleOffset).ToRadian();
            Position = new Point(Position.X + distance * Math.Cos(finalAngle), Position.Y + distance * Math.Sin(finalAngle));
        }

        public void Close()
        {
            Context.Close();
        }

        void IDisposable.Dispose()
        {
            Close();
        }
    }
}